<?php

namespace App\Http\Controllers\AgentAdmin;

use App\Enums\AssetStatus;
use App\Enums\OrderStatus;
use App\Enums\ProductStatus;
use App\Enums\ProductType;
use App\Enums\WalletStatus;
use App\Models\AgentConfig;
use App\Models\AgentUser;
use App\Models\Asset;
use App\Models\FrontendUser;
use App\Models\MergeOrder;
use App\Models\MergeOrderItem;
use App\Models\Order;
use App\Models\Product;
use App\Models\ProductToken;
use App\Services\ProductService;
use App\Services\SdPayService;
use App\Utils\ShortUrl;
use DB;
use Vinlon\Laravel\LayAdmin\Exceptions\AdminException;
use Vinlon\Laravel\LayAdmin\PaginateResponse;

class BusinessController
{
    /** @var ProductService */
    private $productService;

    public function __construct(ProductService $productService)
    {
        $this->productService = $productService;
    }

    /** 查询在售的转售商品列表 */
    public function listResaleProducts()
    {
        /** @var AgentUser $user */
        $user = auth()->user();

        $query = $this->productService
            ->getAgentProductQuery($user->agent_id)
            ->when(request()->keyword, function ($q) {
                $likeVal = '%' . request()->keyword . '%';

                return $q->where('name', 'like', $likeVal);
            })
            ->when(request()->min_price, function ($q) {
                return $q->where('price', '>=', toFen(request()->min_price));
            })
            ->when(request()->max_price, function ($q) {
                return $q->where('price', '<=', toFen(request()->max_price));
            })
            ->when(request()->lock_status, function ($q) {
                if ('no' == request()->lock_status) {
                    return $q->where('left_count', '>', 0);
                }

                return $q->where('left_count', '<=', 0);
            })
            ->with(['resale_user.auth'])
            ->where('type', ProductType::RESALE)
            ->where('status', ProductStatus::ON_SALE)
            ->orderByDesc('id');

        return paginate_result($query);
    }

    /** 根据筛选条件锁单 */
    public function lockResaleProducts()
    {
        /** @var AgentUser $user */
        $user = auth()->user();

        request()->validate([
            'locker_mobile' => 'required',
            'lock_minutes' => 'required',
            'min_price' => 'required',
            'max_price' => 'required',
        ]);

        /** @var FrontendUser $locker */
        $locker = FrontendUser::query()->where('agent_id', $user->agent_id)
            ->where('mobile', request()->locker_mobile)->first();

        if (!$locker) {
            throw new AdminException('锁单账号不存在');
        }
        if (!$locker->wallet || $locker->wallet->status->isNot(WalletStatus::OPENED)) {
            throw new AdminException('锁单账号未开通钱包');
        }

        $productQuery = $this->productService
            ->getAgentProductQuery($user->agent_id)
            ->when(request()->keyword, function ($q) {
                $likeVal = '%' . request()->keyword . '%';

                return $q->where('name', 'like', $likeVal);
            })
            ->when(request()->min_price, function ($q) {
                return $q->where('price', '>=', toFen(request()->min_price));
            })
            ->when(request()->max_price, function ($q) {
                return $q->where('price', '<=', toFen(request()->max_price));
            })
            ->where('left_count', '>', 0)
            ->where('resale_user_id', '!=', $locker->id)
            ->where('type', ProductType::RESALE)
            ->where('status', ProductStatus::ON_SALE);

        $lockUntil = now()->addMinutes(request()->lock_minutes);

        $beforeCount = $productQuery->count();

        $lockCount = 0;
        while (true) {
            if ($lockCount >= 50) {
                break;
            }
            /** @var Product $product */
            $product = $productQuery->first();
            if (!$product) {
                break;
            }
            // 创建订单
            $order = new Order();
            $order->agent_id = $user->agent_id;
            $order->user_id = $locker->id;
            $order->order_no = Order::generateOrderNo($product->type);
            $order->product_id = $product->id;
            $order->product_name = $product->name;
            $order->product_logo_url = $product->logo_url;
            $order->quantity = 1;
            $order->sale_price = $product->price;
            $order->order_amount = $product->price;
            $order->is_resale = true;
            $order->manual_lock_until = $lockUntil;

            $order->order_status = OrderStatus::NOT_PAY;

            \DB::transaction(function () use ($product, $order) {
                $order->save();
                // 库存更新
                $product->decrement('left_count', $order->quantity);
                $product->increment('sales_count', $order->quantity);
            });
            ++$lockCount;
        }
        $afterCount = $productQuery->count();

        return [
            'lock_count' => $lockCount,
            'before_count' => $beforeCount,
            'after_count' => $afterCount,
        ];
    }

    /** 查询手动锁定的订单 */
    public function listLockedOrders()
    {
        /** @var AgentUser $user */
        $user = auth()->user();

        $query = Order::query()
            ->where('agent_id', $user->agent_id)
            ->whereNotNull('manual_lock_until')
            ->whereIn('order_status', [OrderStatus::MERGE_PAYING, OrderStatus::NOT_PAY])
            ->when(request()->locker_mobile, function ($q) use ($user) {
                /** @var FrontendUser $locker */
                $locker = FrontendUser::query()->where('agent_id', $user->agent_id)
                    ->where('mobile', request()->locker_mobile)->first();
                $lockerId = $locker ? $locker->id : 0;
                $q->where('user_id', $lockerId);
            })
            ->when(request()->min_price, function ($q) {
                return $q->where('sale_price', '>=', toFen(request()->min_price));
            })
            ->when(request()->max_price, function ($q) {
                return $q->where('sale_price', '<=', toFen(request()->max_price));
            })
            ->with(['product.resale_user.auth', 'user.auth'])
            ->orderByDesc('id');

        return paginate_result($query);
    }

    /** 批量解锁 */
    public function batchUnLock()
    {
        /** @var AgentUser $user */
        $user = auth()->user();

        request()->validate([
            'order_ids' => 'required | array',
        ]);
        $orderIds = request()->order_ids;
        $orderQuery = Order::query()
            ->where('agent_id', $user->agent_id)
            ->where('order_status', OrderStatus::NOT_PAY)
            ->where('is_resale', true)
            ->whereNotNull('manual_lock_until')
            ->whereIn('id', $orderIds);
        $productIds = $orderQuery->get()->pluck('product_id');
        $orderQuery->update(['order_status' => OrderStatus::CANCEL]);

        //批量修改产品状态
        $productQuery = Product::query()->whereIn('id', $productIds)
            ->where('left_count', 0)
            ->where('sales_count', 1);

        $productQuery->update([
            'left_count' => 1,
            'sales_count' => 0,
        ]);

        return [
            'cancel_order_count' => count($productIds),
        ];
    }

    /** 多笔订单合并支付 */
    public function mergePay()
    {
        /** @var AgentUser $agentUser */
        $agentUser = auth()->user();

        request()->validate([
            'order_ids' => 'required | array',
        ]);
        $orderIds = request()->order_ids;
        if (count($orderIds) > 20) {
            return new AdminException('最多支持20笔订单');
        }
        $orders = $this->getLockOrderQuery($orderIds)
            ->where('order_status', OrderStatus::NOT_PAY)
            ->with(['user', 'product.resale_user'])
            ->get();

        if ($orders->count() != count($orderIds)) {
            throw new AdminException('无效的订单，请重新选择');
        }

        $totalAmount = 0;
        $orderDesc = '合并支付';
        $extra = [
            'orderDesc' => $orderDesc,
            'accountingMode' => '1', //入账模式：  1:即时确认（默认）  2:担保
        ];
        $user = null;
        $payConfigs = AgentConfig::query()
            ->where('agent_id', $agentUser->agent_id)
            ->whereIn('config_key', [
                AgentConfig::SDPAY_MERCH_NO,
                AgentConfig::SDPAY_RSA_PRIVATE_KEY,
                AgentConfig::PAY_RESALE_AGENT_FEE_RATE,
            ])
            ->pluck('config_value', 'config_key')
            ->toArray();
        $resaleServiceRate = \Arr::get($payConfigs, AgentConfig::PAY_RESALE_AGENT_FEE_RATE, 0);
        $merchantNo = \Arr::get($payConfigs, AgentConfig::SDPAY_MERCH_NO);
        $payeeList = [];
        $totalServiceFee = 0;
        $mergeOrderItems = [];
        /** @var Order $order */
        foreach ($orders as $order) {
            if (null == $user) {
                $user = $order->user;
            } elseif ($user != $order->user) {
                throw new AdminException('所有订单必须属于同一个人');
            }
            $product = $order->product;
            $resaleUser = $product->resale_user;
            if (!$resaleUser->wallet || $resaleUser->wallet->status->isNot(WalletStatus::OPENED)) {
                throw new AdminException('资产转售人' . $resaleUser->mobile . '未开通钱包，无法支付');
            }
            $walletNo = $resaleUser->wallet->wallet_user_no;
            $totalAmount += $order->order_amount;
            $serviceFee = 0;
            if ($resaleServiceRate > 0) {
                $serviceFee = intval($order->order_amount * ($resaleServiceRate / 100));
            }
            $totalServiceFee += $serviceFee;
            $userRecvAmt = $order->order_amount - $serviceFee;
            if (!\Arr::has($payeeList, $walletNo)) {
                $payeeList[$walletNo] = [
                    'recvUserId' => $walletNo,
                    'recvCustomerOrderNo' => uniqid(),
                    'recvAmt' => toYuan($userRecvAmt),
                    'remark' => $orderDesc,
                ];
            } else {
                $payeeList[$walletNo]['recvAmt'] = toYuan(toFen($payeeList[$walletNo]['recvAmt']) + $userRecvAmt);
            }
            $mergeOrderItems[] = [
                'created_at' => now(),
                'updated_at' => now(),
                'order_id' => $order->id,
                'order_amount' => $order->order_amount,
                'service_fee' => $serviceFee,
            ];
        }
        if (count($payeeList) > 9) {
            throw new AdminException('支付通道最多支持向9个人付款');
        }
        $extra['payer'] = [
            'payUserId' => $user->wallet->wallet_user_no,
            'accountType' => '0',
        ];
        if ($totalServiceFee > 0) {
            //收取手续费
            $payeeList[$merchantNo] = [
                'recvUserId' => $merchantNo,
                'recvCustomerOrderNo' => uniqid(),
                'recvAmt' => toYuan($totalServiceFee),
                'remark' => $orderDesc . '手续费',
            ];
        }
        $extra['payeeList'] = array_values($payeeList);
        $mergeOrderNo = 'M' . now()->format('YmdHis') . rand(1000, 9999);
        $mergeOrder = new MergeOrder();
        $mergeOrder->order_no = $mergeOrderNo;
        $mergeOrder->order_amount = $totalAmount;

        //生成支付链接
        $sdPayService = new SdPayService($payConfigs);
        $payLink = $sdPayService->getUnionPayLink(
            $mergeOrderNo,
            toYuan($totalAmount),
            $orderDesc,
            md5($user->mobile),
            $user->wallet->wallet_user_no,
            'https://walpay.sandpay.com.cn/balanceDetails',
            now()->addMinutes(10),    //订单有效期10分钟
            $extra
        );
        DB::transaction(function () use ($mergeOrder, $mergeOrderItems, $orderIds) {
            $mergeOrder->save();
            foreach ($mergeOrderItems as &$item) {
                $item['merge_order_id'] = $mergeOrder->id;
            }
            MergeOrderItem::query()->insert($mergeOrderItems);
            //订单状态修改为合并支付中...
            $this->getLockOrderQuery($orderIds)
                ->where('order_status', OrderStatus::NOT_PAY)
                ->update(['order_status' => OrderStatus::MERGE_PAYING]);
        });

        return [
            'payee_list' => $payeeList,
            'pay_link' => ShortUrl::make($payLink),
        ];
    }

    /** 取消合并支付 */
    public function cancelMergePay()
    {
        request()->validate([
            'order_id' => 'required',
        ]);
        /** @var MergeOrderItem $mergeItem */
        $mergeItem = MergeOrderItem::query()
            ->where('order_id', request()->order_id)
            ->whereHas('merge_order', function ($q) {
                return $q->where('status', OrderStatus::NOT_PAY);
            })
            ->first();
        if (!$mergeItem) {
            throw new AdminException('该订单不是【合并支付中】的状态');
        }
        $mergeOrder = $mergeItem->merge_order;
        $mergeOrder->status = OrderStatus::CANCEL;
        $mergeOrder->save();
        $orderIds = $mergeOrder->items()->pluck('order_id');

        //订单状态修改为未支付
        $count = $this->getLockOrderQuery($orderIds)
            ->where('order_status', OrderStatus::MERGE_PAYING)
            ->update(['order_status' => OrderStatus::NOT_PAY]);

        return [
            'cancel_order_count' => $count,
        ];
    }

    /** 查询用户持有的资产 */
    public function listUserAssets()
    {
        request()->validate([
            'mobile' => 'nullable',
            'second_pass' => 'nullable',
        ]);
        if (!request()->mobile || !request()->second_pass) {
            throw new AdminException('请输入手机号和二级密码查询要批量操作的用户的资产');
        }
        $user = $this->findUser(request()->mobile);
        if (!$user) {
            throw new AdminException('用户未找到');
        }
        if (!\Hash::check(request()->second_pass, $user->second_pass)) {
            throw new AdminException('二级密码不正确');
        }
        if (!$user->wallet || $user->wallet->status->isNot(WalletStatus::OPENED)) {
            throw new AdminException('用户未开通钱包');
        }

        $page = request()->page ?: 1;
        $limit = request()->limit ?: 10;

        $assetProducts = Asset::query()
            ->where('user_id', $user->id)
            ->whereIn('asset_status', [AssetStatus::HOLD, AssetStatus::ON_SALE, AssetStatus::EXCHANGED])
            ->select([
                'contract_address',
                DB::raw('count(*) as total_count'),
                DB::raw('sum(case when asset_status = "' . AssetStatus::HOLD . '" then 1 else 0 end) as hold_count'),
                DB::raw('sum(case when asset_status = "' . AssetStatus::ON_SALE . '" then 1 else 0 end) as onsale_count'),
            ])->groupBy('contract_address')
            ->with(['product'])
            ->orderByDesc('total_count')
            ->get()->toArray();

        return new PaginateResponse(
            count($assetProducts),
            array_splice($assetProducts, $limit * ($page - 1), $limit)
        );
    }

    /** 查询指定用户的资产存证信息 */
    public function listUserAssetTokens()
    {
        request()->validate([
            'mobile' => 'required',
            'contract_address' => 'required',
        ]);
        $user = $this->findUser(request()->mobile);

        $perPrice = Product::query()
            ->where('contract_address', request()->contract_address)
            ->where('resale_user_id', $user->id)
            ->where('status', ProductStatus::ON_SALE)
            ->select([
                'price',
                DB::raw('count(*) as total_count'),
                DB::raw('sum(case when left_count=1 then 1 else 0 end) as free_count'),
                DB::raw('sum(case when left_count=0 then 1 else 0 end) as lock_count'),
            ])
            ->groupBy(['price'])
            ->orderBy('price')
            ->get()->toArray();
        $page = request()->page ?: 1;
        $limit = request()->limit ?: 10;

        return new PaginateResponse(count($perPrice), array_splice($perPrice, $limit * ($page - 1), $limit));
    }

    /** 批量转售 */
    public function batchResale()
    {
        request()->validate([
            'mobile' => 'required',
            'contract_address' => 'required',
            'quantity' => 'required',
            'price' => 'required',
        ]);
        $quantity = request()->quantity;
        if ($quantity > 50) {
            throw new AdminException('最大批量转售数量为50');
        }
        $contractAddress = request()->contract_address;
        $resalePrice = request()->price;
        $user = $this->findUser(request()->mobile);
        $assets = Asset::query()
            ->where('user_id', $user->id)
            ->where('contract_address', $contractAddress)
            ->where('asset_status', AssetStatus::HOLD)
            ->limit($quantity)
            ->get();
        $product = Product::query()
            ->where('contract_address', $contractAddress)
            ->where('type', ProductType::ISSUE)
            ->first();

        if ($assets->count() < $quantity) {
            throw new AdminException('持有资产数量不足');
        }
        foreach ($assets as $asset) {
            \DB::transaction(function () use ($product, $asset, $resalePrice, $user) {
                // 创建转售商品
                $resaleProduct = new Product();
                $resaleProduct->copyFrom($product);
                $resaleProduct->type = ProductType::RESALE();
                $resaleProduct->resale_user_id = $user->id;
                $resaleProduct->issue_count = 1;
                $resaleProduct->left_count = 1;
                $resaleProduct->sales_count = 0;
                $resaleProduct->price = toFen($resalePrice);
                $resaleProduct->online_time = now();
                $resaleProduct->status = ProductStatus::ON_SALE();
                $resaleProduct->save();

                // 创建转售商品的资产凭证
                $resaleToken = new ProductToken();
                $resaleToken->product_id = $resaleProduct->id;
                $resaleToken->token_id = $asset->token_id;
                $resaleToken->save();

                // 原资产标记为转售中
                $asset->asset_status = AssetStatus::ON_SALE();
                $asset->save();
            });
        }
    }

    public function batchCancelResale()
    {
        request()->validate([
            'mobile' => 'required',
            'contract_address' => 'required',
            'cancel_count' => 'required',
            'price' => 'required',
        ]);
        $cancelCount = request()->cancel_count;
        if ($cancelCount > 50) {
            throw new AdminException('最大批量操作数量为50');
        }
        $user = $this->findUser(request()->mobile);
        $products = Product::query()
            ->where('resale_user_id', $user->id)
            ->where('contract_address', request()->contract_address)
            ->where('left_count', 1)
            ->where('price', toFen(request()->price))
            ->where('status', ProductStatus::ON_SALE)
            ->limit($cancelCount)
            ->get();
        if ($products->count() < $cancelCount) {
            throw new AdminException('可取消资产数量不足');
        }

        /** @var Product $product */
        foreach ($products as $product) {
            DB::transaction(function () use ($product, $user) {
                $tokenIds = ProductToken::query()
                    ->where('product_id', $product->id)
                    ->get()->map(function (ProductToken $token) {
                        return $token->token_id;
                    });
                Asset::query()
                    ->where('user_id', $user->id)
                    ->whereIn('token_id', $tokenIds)
                    ->where('asset_status', AssetStatus::ON_SALE)
                    ->update(['asset_status' => AssetStatus::HOLD]);

                $product->status = ProductStatus::STOP;
                $product->save();
            });
        }
    }

    private function getLockOrderQuery($orderIds)
    {
        /** @var AgentUser $agentUser */
        $agentUser = auth()->user();

        return Order::query()
            ->where('agent_id', $agentUser->agent_id)
            ->where('is_resale', true)
            ->whereNotNull('manual_lock_until')
            ->whereIn('id', $orderIds);
    }

    private function findUser($mobile)
    {
        /** @var AgentUser $agentUser */
        $agentUser = auth()->user();

        /* @var FrontendUser $user */
        return FrontendUser::query()->where('agent_id', $agentUser->agent_id)
            ->where('mobile', $mobile)->first();
    }
}
